﻿/**************************************************************
 * Copyright gt1987. All rights reserved.
 * 
 * Author: guitao(guitao@eastmoney.com) 
 * Create Date: 2020/5/8 21:24:37
 * Description: RedisDistributeFeature
 *          
 * Revision History:
 *      Date         Author               Description
 *              
***************************************************************/

using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Text;

namespace gt.TaskScheduler.Core.Components
{
    /// <summary>
    /// 基于Redis实现的分布式组件
    /// </summary>
    public class RedisDistributeFeature : IDistributeFeature
    {
        private IConnectionMultiplexer _connection = null;
        private readonly int _lockExpiredSecond = 3;
        private readonly int _dataExpiredMinute = 60;

        public RedisDistributeFeature(string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString");

            _connection = ConnectionMultiplexer.Connect(connectionString);
        }

        /// <summary>
        /// RedisDistributeFeature
        /// </summary>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="lockExpiredSecond">分布式锁过期时间</param>
        /// <param name="dataExpiredMinute">dataExpiredMinutes 应根据任务执行长度预估，设为预估最大值</param>
        public RedisDistributeFeature(string connectionString, int lockExpiredSecond, int dataExpiredMinute)
        {
            if (string.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString");
            if (lockExpiredSecond <= 0) throw new InvalidOperationException("lockExpiredSecond");
            if (dataExpiredMinute <= 0) throw new InvalidOperationException("dataExpiredMinute");

            _connection = ConnectionMultiplexer.Connect(connectionString);
            _lockExpiredSecond = lockExpiredSecond;
            _dataExpiredMinute = dataExpiredMinute;
        }

        /// <summary>
        /// 删除集群数据
        /// </summary>
        public void DeleteData(string key)
        {
            _connection.GetDatabase().KeyDelete(key, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 删除集群数据
        /// </summary>
        public void DeleteData(string key, string field)
        {
            _connection.GetDatabase().HashDelete(key, field, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 获取并移除有序队列的下一个数据
        /// </summary>
        public string Dequeue(string key)
        {
            return _connection.GetDatabase().ListRightPop(key, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 设置一个有序队列数据
        /// </summary>
        public void Enqueue(string key, List<string> datas)
        {
            foreach (var d in datas)
            {
                _connection.GetDatabase().ListLeftPush(key, d, When.Always, CommandFlags.DemandMaster);
            }
        }
        /// <summary>
        /// 获取某个key 对应的所有数据
        /// </summary>
        public Dictionary<string, string> GetAllData(string key)
        {
            var result = _connection.GetDatabase().HashGetAll(key, CommandFlags.DemandMaster);
            if (result == null) return null;
            return Array.ConvertAll(result, x => new KeyValuePair<string, string>(x.Name, x.Value)).ToDictionary();
        }
        /// <summary>
        /// 获取集群数据
        /// </summary>
        public string GetData(string key, string field)
        {
            return _connection.GetDatabase().HashGet(key, field, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 设置或更新集群数据
        /// </summary>
        public void SetData(string key, string field, string value)
        {
            _connection.GetDatabase().HashSet(key, field, value);
            _connection.GetDatabase().KeyExpire(key, TimeSpan.FromMinutes(_dataExpiredMinute), CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 获取分布式锁
        /// </summary>
        /// <returns></returns>
        public bool GetLock(string key, string lockValue)
        {
            var expired = TimeSpan.FromSeconds(_lockExpiredSecond);
            return _connection.GetDatabase().LockTake(key, lockValue, expired, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 释放锁
        /// </summary>
        public bool ReleaseLock(string key, string lockValue)
        {
            return _connection.GetDatabase().LockRelease(key, lockValue, CommandFlags.DemandMaster);
        }
        /// <summary>
        /// 释放相关托管资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // 释放托管状态(托管对象)。
                _connection.Dispose();
            }

            // 将大型字段设置为 null。
            _connection = null;
        }
    }
}
